/*->c.xmodem */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <string.h>


#include "h.os"
#include "h.wimp"
#include "h.sprite"
#include "h.werr"
#include "h.wimpt"
#include "h.bbc"
#include "h.akbd"


#include "h.def"

#include "h.wos"
#include "h.timex"

#include "h.serial"

#include "h.view"
#include "h.mym"
#include "h.batch"
#include "h.ftp"


#include "h.xmodem"


/**************************************************************************/


#define NIL     -2

#define AUTO     0
#define CRC      2
#define CHK      1

#define TIMEOUT -1
#define CANNED  -2
#define RETRIED -3
#define BLOSYNC -4
#define ABORT   -5
#define FILESYS -6
#define CD      -7
#define GERROR  -8

#define MAXRET  25



static int  xmretry=MAXRET;  /* maximum number of retries for one block */
static int  xmsize;          /* current block size */
static int  ymb;             /* ymodem batch flag  */


static int  ysbyte;          /* count down of bytes left to rx in ymodem
                                batch */

static char xmstart;         /* block start char */
static char xmgo1;           /* ftp init chars  C, NAK, G */
static char xmgo2;
static char xmgo3;

static char * ymbp;          /* pointer to zero block for ymodem batch */

static char ymgmode;         /* flag overthruster mode */


static int  xsize;
       int  xmode=1;
       int  ymode=1;
       int  ysize;

/*****************************************************************************/




/****************************************************************************/


char * xmerr(int err)
{
 switch(err)
  {
   case FILESYS:return("{XM00}");break; /* Filing system error */
   case TIMEOUT:return("{XM01}");break; /* Transfer timed out */
   case CANNED :return("{XM02}");break; /* Transfer cancelled remotely */
   case RETRIED:return("{XM03}");break; /* Cancelled too many retries */
   case BLOSYNC:return("{XM04}");break; /* Cancelled synchronization lost */
   case ABORT  :return("{XM05}");break; /* Transfer cancelled */
   case CD     :return("{XM06}");break; /* Offline! */
   case GERROR :return("{XM07}");break; /* Error in -g mode */
   case 0      :return("{XM08}");break; /* Transfer complete */
  }
 return("");
}


/****************************************************************************/


typedef struct zeros                   /* block zero data structure */ 
{   int  flen;                         /* file length */ 
    int  fstamp;                       /* file date/time stamp */ 
    char fnam[17];                     /* original file name */ 
    char prog[15];                     /* sending program name */ 
    char fill[88];                     /* reserved for future use */ 
}  zeros;


/***************************************************************************/

static void ackchk(void);
static void sendack(int,int);
static char * getblock(char *);

/*************************************************************************/

#define WINDOW 6                       /* maximum size of window */ 
 
static int outblk;                     /* number of next block to send */ 
static int ackblk;                     /* number of last block ACKed */ 
static int blksnt;                     /* number of last block sent */ 
static int slide;                      /* true if sliding window */ 
static int ackst;                      /* ACK/NAK state */ 
static int numnak;                     /* number of sequential NAKs */ 
static int chktec;                     /* check type, 1=CRC, 0=checksum */ 
static int toterr;                     /* total number of errors */ 
 
/****************************************************************************/


int timerset(int tx)
{
 return(clock()+tx*10);
}


int timeup(int tx)
{
 return(clock()>tx);
}



/*****************************************************************************/

/* physically ship a block */
/* char *blk;                             data to be shipped */ 
/* int blknum;                            number of block */ 
 
static int shipblk(char * blk,int blknum) 
{ 
 char *b = blk;                     /* data pointer */ 
 int crc = 0;                       /* CRC check value */ 
 int n;                             /* index */ 
 
 outbyte(SOH);                     /* block header */ 
 outbyte(blknum);                  /* block number */ 
 outbyte(blknum^0xff);             /* block number check value */ 
 
 for(n=0; n<128; n++)               /* ship the data */ 
 { 
  if(chktec) crc=updcrc(*b,crc); 
  else       crc+=*b; 
  outbyte(*b++); 
 } 
 
 if(chktec)                         /* send proper check value */ 
 {
  crc=finishcrc(crc); 
  outbyte(crc>>8); 
  outbyte(crc&0xff); 
 } 
 else outbyte(crc); 
 
 return(1); 
} 






/* send one block */ 
/* FILE *f      file to read from */ 
/* int blknum   block to send */ 

static void sendblk(FILE * f,int blknum)   
{ 
 int  blkloc;                       /* address of start of block */ 
 char buf[128];                     /* one block of data */ 
 
 if(blknum!=blksnt+1)               /* if jumping */ 
 {
  blkloc=(blknum-1)*128; 
  ftpreadfseek(f,blkloc,0);        /* move where to */ 
 }

 blksnt=blknum; 
 
 memset(buf,26,128);                /* fill buffer with control Zs */ 
 ftpread(buf,1,128,f);             /* read in some data */ 
 shipblk(buf,blknum);               /* pump it out the comm port */ 
} 






/*  File transmitter logic */ 
/*  transmit a file        */ 
 
int xmtfile(int fx) 
{ 
 FILE *f=NULL;                      /* file to send */ 
 int  t1;                           /* timers */ 
 int  endblk;                       /* block number of EOT */ 
 struct zeros zero;                 /* block zero data */ 
 int  error;
 int * p;

 if(fx>-1)                                     /* if sending a file */ 
 {
  memset((char *)&zero,0,sizeof(zero));        /* clear out data block */ 
  zero.fstamp = 0; 
  strcpy(zero.prog,"Hearsay");                 /* prog name */

  strcpy(zero.fnam,vtable[TXBFILE][fx].rname);
  zero.flen=vtable[TXBFILE][fx].stat.length;

  /* fill in file info here */

  p=(int*)(&zero.fill[76]);
  *p++=vtable[TXBFILE][fx].stat.exec;
  *p++=vtable[TXBFILE][fx].stat.load;
  *p=0x3;


  if((f=ftpopenread(fx,0 /* 128 NBB */))==NULL)
  {
   error=FILESYS;
   goto abort;
  }
 
  endblk = ((zero.flen+127)/128) + 1;
 }
 else
  endblk = 0;                          /* fake for no file */ 
 
 outblk=1;                             /* set starting state */ 
 ackblk=-1; 
 blksnt=slide=ackst=numnak=toterr=0; 
 chktec=2;                             /* undetermined */ 
 
 t1=timerset(300);                     /* time limit for first block */
 
 ftpinfo("{XM09}"); 
 
 while(ackblk<endblk)               /* while not all there yet */ 
 {    
  if(!ftponline())
  {
   error=CD;
   goto abort;
  }

  if(ftp_ok==0)
  {
   error=ABORT;
   goto abort;
  }
 
  if(timeup(t1))
  {
   error=TIMEOUT;
   goto abort;
  }

  if(ftpreaderror(f))
  {
   error=FILESYS;
   goto abort;
  }

  if(outblk<=ackblk+(slide? WINDOW : 1)) 
  {
   if(outblk<endblk) 
   {
    if(outblk>0) sendblk(f,outblk); 
    else         shipblk((char *)&zero,0);

    ftpinfo("{XM10} %d ",outblk); /*  Sending block #%d */
   } 
   else if(outblk==endblk) outbyte(EOT);
 
   outblk++; 
   t1=timerset(300);      /* time limit between blocks */ 
  } 
 
  ackchk(); 
  if(numnak>MAXRET)
  {
   error=RETRIED;
   goto abort;
  } 
 }
 
 if(endblk) 
 {
  if(f) ftpcloseread(f,xmerr(0),0);
 }

 return(0);      
 
abort:
      if(f) ftpcloseread(f,xmerr(error),error!=0?FTPCLOSEERROR:0);
      return(error);
} 
 


/*  The various ACK/NAK states are: 
    0:   Ground state, ACK or NAK expected. 
    1:   ACK received 
    2:   NAK received 
    3:   ACK, block# received 
    4:   NAK, block# received 
    5:   Returning to ground state */
 

 
static void ackchk(void)               /* check for ACK or NAK */ 
{ 
 int c;                             /* one byte of data */ 
 static int rawblk;                 /* raw block number */ 

 while((c=ftpgetbyte(0))!=EOF) 
 {
  if(ackst==3 || ackst==4) 
  {
   slide = 0;               /* assume this will fail */ 
   if(rawblk==(c^0xff))     /* see if we believe the number */ 
   {
    rawblk=outblk-((outblk-rawblk)&0xff); 
    if(rawblk>=0 && rawblk<=outblk && rawblk>outblk-20) 
    { 
     slide = 1;     /* we have sliding window! */ 
     if(ackst==3) 
      ackblk = ackblk>rawblk? ackblk : rawblk; 
     else 
     {
      outblk=rawblk<0?0:rawblk; 
      ftpflushoutput();    /* purge pending output */ 
     } 

     ftpinfo(" %d",ackst==3?"{XMACK}":"{XMNAK}",rawblk);
    } 
   } 
   ackst=5;               /* return to ground state */ 
  } 
 
  if(ackst==1 || ackst==2) 
  {
   rawblk=c; 
   ackst+=2; 
  } 
 
  if(!slide || ackst==0) 
  {
   if(c==ACK) 
   {
    if(!slide) 
    {
     ackblk++; 
     ftpinfo("{XMACK} %d",ackblk);
     ftpbloinc();
    } 
    ackst=1; 
    numnak=0;
    ftpbloinc();
   } 
   else
   if(c=='C' || c==NAK) 
   {
    if(chktec>1)             /* if method not determined yet */ 
    {
     chktec=(c=='C');  /* then do what rcver wants */
     ftpsetmode(chktec?"{XM11}":"{XM12}");
    }
                   
    if(!slide) 
    {
     outblk=ackblk+1; 
     ftpinfo("{XMNAK} %d",ackblk+1);
    } 
    ackst=2; 
    numnak++; 
    if(blksnt)
    {
     toterr++;
     ftpretinc();
    } 
   } 
  }  
  if(ackst==5) ackst = 0; 
 } 
} 
 



 
   /* - - - - - - - - - - - - -  - -  - -  - -  - - - - - - - - - - - */

/*  File receiver logic */ 
 
int rcvfile(void) 
{ 
 int c;                             /* received character */ 
 int tries;                         /* retry counter */ 
 int t1;                            /* timer */ 
 int blknum;                        /* desired block number */ 
 int inblk;                         /* this block number */ 
 FILE *f=NULL;                      /* file, opener */ 
 char buf[128];                     /* data buffer */ 
 struct zeros zero;                 /* file header data storage */
 int endblk;                        /* block number of EOT, if known */ 
 int left;                          /* bytes left to output */ 
 int n;                             /* index */ 
 char *stat="Init";                 /* receive block status */ 
 char *why;                         /* single block receiver, status */ 
 
 int error;

 ftpsetmode("{XM11}");
 
 blknum = 0;                             /* first block we must get */ 
 tries = -10;                            /* kludge for first time around */ 
 chktec = 1;                             /* try for CRC error checking */ 
 toterr = 0;                             /* no errors yet */ 
 endblk = 0;                             /* we don't know the size yet */ 
 memset((char *)&zero,sizeof(zero),0);   /* or much of anything else */ 
 
nakblock:                                /* we got a bad block */ 
 if(blknum>1)
 {
  toterr++;
  ftpretinc();
 }
 
 if(++tries>MAXRET) 
 {
  error=RETRIED;
  goto abort;
 }
 
 if(tries==0)                          /* if CRC isn't going */ 
 {
  chktec = 0;                          /* then give checksum a try */ 
  ftpsetmode("{XM12}");
 }


 sendack(0,blknum);                    /* send the NAK */ 
 ftpinfo("  {XMNAK} %d %-5s",blknum,stat);
 goto nextblock; 
 
ackblock:                              /* we got a good block */ 
 ftpinfo("  {XMACK} %d %-5s",blknum-1,stat); 

nextblock:                             /* start of "get a block" */ 
 stat = "";

 if(ftp_ok==0)
 {
  error=ABORT;
  goto abort;
 }

 if(!ftponline())
 {
  error=CD;
  goto abort;
 }
     

 t1=timerset(50);                 /* timer to start of block */ 


 while(!timeup(t1)) 
 {
  c=ftpgetbyte(0); 

  if(c==EOT) 
  {
   if(!endblk || endblk==blknum) goto endrcv; 
  } 
  else
  if(c==SOH) 
  {
   inblk=ftpgetbyte(50); 
   if(ftpgetbyte(50) == (inblk^0xff)) 
   goto blockstart;    /* we found a start */ 
  } 
 } 
 stat = "Time"; 
 goto nakblock; 
 
blockstart:                            /* start of block detected */ 
 c = blknum&0xff; 
 if(inblk==0 && blknum<=1)          /* if this is the header */ 
 {
  if((why=getblock((char *)&zero))==0) 
  {
   sendack(1,inblk);        /* ack the header */
   ftpbloinc();
                                                      /* length to transfer */ 
   if((left=zero.flen)!=0) endblk = (left+127)/128 + 1; 

   if(!f)
     if((f=ftpopenwrite(zero.fnam,NULL,0 /* zero.flen/128 NBB */,
                                 zero.flen,NULL,(int*)(zero.fill+84)))==NULL)
     {
      error=FILESYS;
      goto abort;
     }

   blknum=1;              /* now we want first data block */ 
   goto ackblock; 
  } 
  else 
  {
   stat=why; 
   goto nakblock;           /* bad header block */ 
  } 
 } 
 else
 if(inblk==c)                     /* if this is the one we want */ 
 {
  if((why=getblock(buf))==0)      /* else if we get it okay */ 
  {
   sendack(1,inblk);              /* ack the data */ 


#ifdef NEVER
              for(n=0; n<128; n++) 
              {    if(endblk)          /* limit file size if known */ 
                   {    if(!left) 
                             break; 
                        left--; 
                   } 
                   if(fputc(buf[n],f)==EOF) 
                                            {error=FILESYS; goto abort;} 
              } 
#endif

   if(endblk)
    left-=ftpwrite(buf,1,left<128?left:128,f);
   else
    ftpwrite(buf,1,128,f);

   if(ftpwriteerror(f))
   {
    error=FILESYS;
    goto abort;
   }

   tries=0;                 /* reset try count */ 
   blknum++;                /* we want the next block */ 
   goto ackblock; 
  } 
  else 
  {
   stat=why; 
   goto nakblock;           /* ask for a resend */ 
  } 
 } 
 else
 if(inblk<c || inblk>c+100)    /* else if resending what we have */ 
 {
  getblock(buf);                /* ignore it */ 
  sendack(1,inblk);             /* but ack it */ 
  stat = "Dup"; 
  goto ackblock; 
 } 
 else
  goto nextblock;               /* else if running ahead */ 
 
endrcv: 
 sendack(0,blknum); 
 ftpinfo("{XM13}");  /* NAK EOT */
 if(ftpgetbyte(200)!=EOT) goto nakblock; 
 sendack(1,blknum); 
 ftpinfo("{XM14}"); 
 
 if(blknum>1)                       /* if we really got anything */ 
 {     
  if(f) ftpclosewrite(f,xmerr(0),0);      /* recvd OK */
  return(0);                        /* signal what file we got */ 
 } 
 else                               /* else no real file */ 
 {
/*  ftpclosewrite(f,xmerr(0),0); */
  return(1);                        /* signal end of transfer */ 
 } 
 
abort:
 if(f) ftpclosewrite(f,xmerr(error),error!=0?FTPCLOSEERROR:0); 
 return(error); 
} 



/* send an ACK or a NAK */ 
/* acknak 1=ACH, 0=NAK  */ 
/* blknum block number  */ 
 
static void sendack(int acknak,int blknum)
{ 
 if(acknak)                         /* send the right signal */ 
         outbyte(ACK); 
 else
 if(chktec) 
         outbyte('C'); 
 else 
         outbyte(NAK); 
 
 outbyte(blknum);                  /* block number */ 
 outbyte(blknum^0xff);             /* block number check */ 
} 
 


static char * getblock(char * buf)      /* read a block of data */ 
{ 
 int ourcrc=0;
 int hiscrc;                            /* CRC check values */ 
 int c;                                 /* one byte of data */ 
 int n;                                 /* index */ 
 
 for(n=0; n<128; n++) 
 {
  if((c=ftpgetbyte(50))==EOF) return "Short"; 
 
  if(chktec) 
   ourcrc=updcrc(c,ourcrc); 
  else
   ourcrc += c; 

  *buf++ = c; 
 } 
 
 if(chktec) 
 {
  ourcrc=finishcrc(ourcrc);
  hiscrc=ftpgetbyte(50)<<8;
  hiscrc|=ftpgetbyte(50); 
 } 
 else 
 {
  ourcrc&=0xff; 
  hiscrc=ftpgetbyte(50) & 0xff; 
 } 

 if(ourcrc==hiscrc) return(NULL);           /* block is good */ 
 else
 if(chktec)         return("CRC");          /* else CRC error */ 
 else               return("Check");        /* or maybe checksum error */ 
}



/****************************************************************************/


void xmchk(char * fbuff,int mode)
{
 int i;
 int j;
 int k;
 int crc;
 j=0;

 if(mode==CHK)
 {
  for(i=0;i<xmsize;i++) j=j+fbuff[i];
  fbuff[xmsize]=j;
  return;
 }

 crc=0;
 k=xmsize;
 i=0;

 while(k--) crc=updcrc(fbuff[j++],crc);
 crc=finishcrc(crc);

 fbuff[xmsize+1]=crc;
 fbuff[xmsize]=crc>>8;
}




int xmwait(int i,int j,int k,int delay)
{
 int time;
 int byte;
 int cans;

 time=clock()+delay;
 cans=2;
 
 while(1)
 {
  byte=ftpgetbyte(0);
  if(byte==i || byte==j || byte==k || clock()>=time) return(byte);
  else 
  if(byte<0)
  {
   if(ftp_ok==0) return(ABORT); 
   if(!ftponline()) return(CD);
  }
  else
  if(byte==CAN)
  {
   if(--cans==0) return(CANNED);
  }
  else cans=2;
 }
}





int  xmtx(FILE * fp)
{
 char fbuff[1030];
 char fpack;
 int  fbpoi; 
 int  byte;
 int  mode;
 int  next;

 ftpflushinput();

 ftpinfo("{XM15}");

 byte=xmwait('C',NAK,'G',6000);     /* wait for NAK or C or G */

 if(byte<0) return(byte);             
 else
 if(byte=='C' || byte=='G')
 {
  mode=CRC;
  if(byte=='G') ymgmode=1;
  ftpsetmode(ymgmode?"{XM18}":"{XM11}");
 }       
 else
 {
  mode=CHK;
  ftpsetmode("{XM12}");
 }

 if(ymb) fpack=-1;
 else    fpack=0;

 next=1;

 while(ymb || (!((fp && ftpreadeof(fp)) && next)) )
 {
  if(ftp_ok==0)
  {
   ftpcanit();
   return(ABORT);
  }

  if(!ftponline()) return(CD);

  if(next)
  {
   fbpoi=0;
   fpack++;

   if(!ymb)
   {
    fbpoi=ftpread(fbuff,1,xmsize,fp);
    if(fbpoi==0) break;
    if(ferror(fp)) return(FILESYS);
    ftpbloinc();
   }
   else
   {
    /* while(fbpoi<xmsize) fbuff[fbpoi++]=ymbp[fbpoi]; */
    while(fbpoi<xmsize) {fbuff[fbpoi]=ymbp[fbpoi];fbpoi++;}
   }
   while(fbpoi<xmsize) fbuff[fbpoi++]=26;
   xmchk(fbuff,mode);
  } 

  outbyte(xmstart);
  outbyte(fpack);
  outbyte(255-fpack);

  for(fbpoi=0;fbpoi<xmsize+mode;fbpoi++) outbyte(fbuff[fbpoi]);
    
  if(ymgmode)
  {
   next=1;
   if(ymb) return(0);
   byte=xmwait(NIL,NIL,NIL,1);
   if(byte<-1) return(byte);
  }
  else
  {
   ftpflushinput(); /* flush input buffer */

   byte=xmwait(NAK,ACK,NIL,6000);
   if(byte<0) return(byte);

   if(byte==ACK)
   {
    next=1;
    if(ymb) return(0);
    ftpinfo("{XM16}");
   }
   else
   {
    next=0;
    ftpinfo("{XM17}");
    ftpretinc();
   }
  }

 }

 do
 {
  outbyte(EOT);
  byte=xmwait(NAK,ACK,NIL,6000);
  if(byte<0) return(byte);
 } while(byte!=ACK);

 return(0);
}


/*****************************************************************************/
/*  XMODEM RECEIVE CODE  */


int xmrxpack(char * fbuff,int mode)
{
 int i;
 int fbpoi;
 int byte;

 for(fbpoi=0;fbpoi<(xmsize+mode);fbpoi++)
 {
  byte=ftpgetbyte(100);
  if(byte<0)
  {
   return(-1);
  }
  fbuff[fbpoi]=byte;
 }


 i=fbuff[xmsize];

 byte=fbuff[xmsize+1];

 xmchk(fbuff,mode);

 if(i!=fbuff[xmsize]) return(-2);

 if(mode==CRC && byte!=fbuff[xmsize+1]) return(-2);

 return(0);
}



int  xmrx(FILE *fp)
{
 char fbuff[1030];
 char fpack;
 int  fbpoi;
 int  byte;
 int  i;
 int  mode;
 int  retryc;
 int  good;

 if(ymb) fpack=0;
 else    fpack=1;

 ftpflushinput(); 

 byte=-1;

 if(xmgo1=='C' || xmgo3=='G')
 {
  for(i=0;i<3;i++)
  {
   if(!ymgmode) ftpflushinput();   /* flush input buffer */

   if(xmgo1=='C') outbyte('C');
   else           outbyte('G');            

   if((byte=xmwait(SOH,xmstart,NIL,300))>0) break; 
  } 
 }

 retryc=xmretry;

 if(byte<0)
 {
  mode=CHK;
  good=-1;
  if(xmgo2==NIL) return(RETRIED);
  ftpsetmode("{XM12}");
 }
 else
 {
  mode=CRC;
  good=0;
  ftpsetmode(ymgmode?"{XM18}":"{XM11}");
 }
 
  
 do
 {
  if(good==1)
  {
   if(!ymgmode) outbyte(ACK);
   if(ymb) return(0);
   retryc=xmretry;
  }
  else
  if(good==-1)
  {
   if(ymgmode)       /* if an error in g mode then can it */
   {
    ftpcanit();
    return(GERROR);
   }

   while(ftpgetbyte(100)>=0);
   outbyte(NAK);
   retryc--;
   ftpretinc();
   if(retryc==0) return(RETRIED);
  }
     
  if(good!=0)
  {
   good=-1;
   byte=xmwait(SOH,EOT,xmstart,300);
   if(byte==-2) return(byte);
   if(byte==-1) continue;
  }

  if(byte==EOT)
  {
   outbyte(ACK);
   break;
  }
  else 
  if(byte==STX) xmsize=1024;
  else
  if(byte==SOH) xmsize=128;                  

  good=-1;
     
  i=ftpgetbyte(100);
  if(i<0) continue;
                                
  byte=ftpgetbyte(100);
  if(byte<0) continue;

  if((byte+i)!= 0xFF)
  {
   ftpinfo("{XM19}");
   xmrxpack(fbuff,mode);
   continue;
  }

  if(i==fpack)
  {
   if(xmrxpack(fbuff,mode)<0)
   {
    ftpinfo("{XM20}");
    continue;
   }
   else
   {
    if(ymb)
    {
     for(fbpoi=0;fbpoi<xmsize;fbpoi++) ymbp[fbpoi]=fbuff[fbpoi];
    }
    else
    {
     ysbyte-=ftpwrite(fbuff,1,(ysbyte>=0 && ysbyte<xmsize)?ysbyte:xmsize,fp);
     if(ferror(fp)) return(FILESYS);
     ftpbloinc();
    }

    fpack++;
    good=1;
    ftpinfo("{XM21}");
   }
  }
  else 
  if(i==(fpack-1))
  {
   xmrxpack(fbuff,mode);
   good=1;
   ftpinfo("{XM22}");
  }
  else return(BLOSYNC);                  
 } while(ftp_ok!=0 && ftponline());

 if(ftp_ok==0)
 {
  ftpcanit();
  return(ABORT);
 }

 if(!ftponline()) return(CD);

 return(0);
}



/***************************************************************************/
/* variables:

      xmgo1   set to C for CRC else NIL
      xmgo2   set to NAK for CHK else NIL
      xmgo3   set to G for -g mode else NIL
     xmsize   packet length set to 1024 for YMODEM tx else 128
    xmretry   number of retries
    xmstart   set to STX for YMODEM set to SOH for XMODEM                 */



static void setxmvars(int mode,int size)
{
 ymb=0;
 ysbyte=-1;
 ymgmode=0;

 switch(mode)
 {
  case 0:
         xmgo1='C';
         xmgo2=NIL;
         xmgo3=NIL;
         break;

  case 1:
         xmgo1=NIL;
         xmgo2=NAK;
         xmgo3=NIL;
         break;


  case 2:
         xmgo1='C';
         xmgo2=NAK;
         xmgo3=NIL;
         break;

 case  3:
         xmgo1=NIL;
         xmgo2=NIL;
         xmgo3='G';
         ymgmode=1;
         break;
 }

 switch(size)
 { 
  case 0:
         xmsize=128;
         xmstart=SOH;
         break;

  case 1:
         xmsize=1024;
         xmstart=STX;
         break;
 }
}                 




/*****************************************************************************/
/* Now xmodem 1K tx */

int ymodemytx(int fx)
{
 FILE *fp;
 int   code;

 setxmvars(xmode,1);                                               

 if((fp=ftpopenread(fx,0 /* xmsize NBB */))==NULL) return(FILESYS);

 code=xmtx(fp);

 ftpcloseread(fp,xmerr(code),code!=0?FTPCLOSEERROR:0);

 return(code);
}




void ymodemtx(void)
{
 int fx;
 int ret;

 ret=0;

 while((fx=txbatchnext())>-1 && ret==0)
 {
  ret=ymodemytx(fx);
 }
}


/*****************************************************************************/
/* Xmodem 1K rx */

void ymodemrx(void)
{
 FILE *fp;
 int   code;

 setxmvars(xmode,0);
 xmsize=128;
 xmstart=STX;

 if((fp=ftpopenwrite("Xmodem1K",NULL,0,0,NULL,NULL))==NULL) return;

 code=xmrx(fp);

 ftpclosewrite(fp,xmerr(code),code!=0?FTPCLOSEERROR:0);
}



/*****************************************************************************/
/* Plain old Xmodem tx */

int xmodemxtx(int fx)
{
 FILE * fp;
 int    code;

 setxmvars(xmode,xsize);
 xmstart=SOH;

 if((fp=ftpopenread(fx,0 /* xmsize */))==NULL) return(FILESYS);

 code=xmtx(fp);

 ftpcloseread(fp,xmerr(code),code!=0?FTPCLOSEERROR:0);

 return(code);
}




void xmodemtx(void)
{
 int fx;
 int ret;

 ret=0;

 while((fx=txbatchnext())>-1 && ret==0)
 {
  ret=xmodemxtx(fx);
 }
}


/*****************************************************************************/
/* Plain old Xmodem rx */

void xmodemrx(void)
{
 FILE *fp;
 int   code;

 setxmvars(xmode,xsize);
 xmstart=SOH;

 if((fp=ftpopenwrite("Xmodem",NULL,0,0,NULL,NULL))==NULL) return;

 code=xmrx(fp);

 ftpclosewrite(fp,xmerr(code),code!=0?FTPCLOSEERROR:0);
}


/***************************************************************************/

/* YMODEM BATCH
   0 packet format
   filename.typ + zero byte
   filelength as a decimal string
   a single space
   mod date in octal seconds from Jan 1 1970
   a single space
   file mode = 0
   a single space
   program serial number
   rest must be zeroes
   zero length filename packet terminates transfer.                         */



int ymodemxtx(int fx)
{
 FILE *fp;
 char ymb0[128];
 int  * p; 

 setxmvars(ymode,ysize);
 xmsize=128;
 xmstart=SOH;
 ymb=1;
  
 memset(ymb0,0,128);

 if(fx>-1)
 {
  strcpy(ymb0,vtable[TXBFILE][fx].rname);
  ymbp=ymb0+strlen(ymb0)+1;
  sprintf(ymbp,"%d ",vtable[TXBFILE][fx].stat.length);

  /* fill in file info here */

  p=(int*)(&ymb0[116]);
  *p++=vtable[TXBFILE][fx].stat.exec;
  *p++=vtable[TXBFILE][fx].stat.load;
  *p=0x3;
 }

 ymbp=ymb0;
 ftpinfo(xmerr(ymb=xmtx(NULL)));

 if(ymb<0) return(ymb);

 /* return here on null filename */
 if(fx<0) return(1);

 setxmvars(ymode,ysize);

 if((fp=ftpopenread(fx,0 /* xmsize NBB */))==NULL) return(FILESYS);

 ymb=xmtx(fp);

 ftpcloseread(fp,xmerr(ymb),ymb!=0?FTPCLOSEERROR:0);

 return(ymb);
}



int ymodemxrx(void)
{
 FILE *fp;
 char ymb0[128];
 int  len;

 setxmvars(ymode,ysize);
 xmstart=STX;
 ymb=1;

 ymbp=ymb0;

 ftpinfo(xmerr(ymb=xmrx(NULL)));

 if(ymb<0) return(ymb);

 ymbp=ymbp+strlen(ymb0)+1;
 if(strlen(ymb0)==0) return(1);

 ymb=sscanf(ymbp,"%d",&len);
 setxmvars(ymode,ysize);       /* ! changes ysbyte value */
 ysbyte=len;

 if((fp=ftpopenwrite(ymb0,NULL,0 /* len/xmsize NBB */,
                                    len,NULL,(int*)(ymb0+124)))==NULL)
                                                            return(FILESYS);

 xmstart=STX;
 xmsize=128;
 ymb=xmrx(fp);

 ftpclosewrite(fp,xmerr(ymb),ymb!=0?FTPCLOSEERROR:0);
 return(ymb);
}



void ymodembtx(void)
{
 int fx;
 int ret;

 ret=0;

 while((fx=txbatchnext())>-1 && ret==0)
 {
  ret=ymodemxtx(fx);
 }

 if(ret==0) ymodemxtx(-1);
}



void ymodembrx(void)
{
 while(ymodemxrx()==0);
} 


/*****************************************************************************/
/* SEA Link tx */

void clinktx(void)
{
 int fx;
 int ret;

 xmsize=128;
 ret=0;



 while((fx=txbatchnext())>-1 && ret==0)
 {
  ret=xmtfile(fx);
 }

 if(ret==0) xmtfile(-1);
} 



/*****************************************************************************/
/* SEA Link rx */

void clinkrx(void)
{
 xmsize=128;

 while(rcvfile()==0);
}

/****************************************************************************/

static int tempxmode;
static int tempymode;
static int tempysize;

#ifdef NEVER

void setpopxmodem(void)
{
 int i;
 for(i=0;i<2;i++) tickst(xmodem_menu,i,xmode==(i+1));
}


void decodexmodem(int m2,int m3,int m4)
{                                      
 switch(m2)
 {
  case 0:      /* Checksum */
  case 1:      /* Auto     */
         xmode=1+m2;
         break;
 }

 m3=m4;
}




void setpopymodem(void)
{
 int i;

 for(i=0;i<3;i++) tickst(ymodem_menu,i,ymode==(i+1));
 for(i=3;i<5;i++) tickst(ymodem_menu,i,ysize==(i-3));
}



void decodeymodem(int m2,int m3,int m4)
{
 switch(m2)
 {
  case 0:
  case 1:
  case 2:
         ymode=m2+1;
         break;

  case 3:
  case 4:
         ysize=m2-3;
         break;
 }

 m3=m4;
}

#endif


void xmodemicon(void)
{
 int handle=whandle[TXMODEM];

 if(icon==2) 
 {
  xmode=tempxmode;
  if(buttons==0x4) zapmenu();
 }
 else
 if(icon==0 || icon==1)   /* xmode 1==Checksum, 2==Auto */
 {
  if(tempxmode!=(icon+1))
  {
   tempxmode=icon+1;
   selectst(handle,0,tempxmode==1);
   selectst(handle,1,tempxmode==2);
  }
 }
}

int xmodemsetup(void)
{
 int handle=createwindow(TXMODEM);
 tempxmode=xmode;
 selectst(handle,0,xmode==1);
 selectst(handle,1,xmode==2);
 return(handle);
}


void xmodem1kicon(void)
{
 int handle=whandle[TXMODEM1K];

 if(icon==2) 
 {
  xmode=tempxmode;
  if(buttons==0x4) zapmenu();
 }
 else
 if(icon==0 || icon==1)   /* xmode 1==Checksum, 2==Auto */
 {
  if(tempxmode!=(icon+1))
  {
   tempxmode=icon+1;
   selectst(handle,0,tempxmode==1);
   selectst(handle,1,tempxmode==2);
  }
 }
}




int xmodem1ksetup(void)
{
 int handle=createwindow(TXMODEM1K);
 tempxmode=xmode;
 selectst(handle,0,xmode==1);
 selectst(handle,1,xmode==2);
 return(handle);
}


void ymodemicon(void)
{
 int handle=whandle[TYMODEM];

 if(icon==5) 
 {
  ymode=tempymode;
  ysize=tempysize;
  if(buttons==0x4) zapmenu();
 }
 else
 if(icon==0 || icon==1 || icon==2) /* ymode 1==Checksum, 2==Auto */
 {
  if(icon!=(tempymode-1))
  {
   tempymode=icon+1;
   selectst(handle,0,tempymode==1);
   selectst(handle,1,tempymode==2);
   selectst(handle,2,tempymode==3);
  }
 }
 else
 if(icon==3 || icon==4)
 {
  if(icon!=(tempysize-3))
  {
   tempysize=icon-3;
   selectst(handle,3,tempysize==0);
   selectst(handle,4,tempysize==1);
  }
 }
}


int ymodemsetup(void)
{
 int handle=createwindow(TYMODEM);
 tempymode=ymode;
 tempysize=ysize;
 selectst(handle,0,ymode==1);
 selectst(handle,1,ymode==2);
 selectst(handle,2,ymode==3);
 selectst(handle,3,ysize==0);
 selectst(handle,4,ysize==1);
 return(handle);
}

